﻿using Microsoft.EntityFrameworkCore;

namespace Devonline.AspNetCore.Security;

/// <summary>
/// 重载的数据库上下文, 提供字符串类型主键的默认实现
/// 此基类上下文因为和身份上下文存在相同两个实体对象模型, 因此不可创建于统一数据库中
/// </summary>
public class BaseSecurityDbContext(DbContextOptions options) : BaseSecurityDbContext<Attachment, DataIssue, Email, Feedback, IdCard, LimitList, Log, Message, Parameter, Personal, Region, SensitiveWord, Todo, WhiteList, Certificate, Secret, DataSecret, Resource, ResourceSecret, string>(options);

/// <summary>
/// 提供 TKey 作为主键类型的数据库上下文
/// 此基类上下文因为和身份上下文存在相同两个实体对象模型, 因此不可创建于统一数据库中
/// </summary>
/// <typeparam name="TKey"></typeparam>
public class BaseSecurityDbContext<TKey>(DbContextOptions options) : BaseSecurityDbContext<Attachment<TKey>, DataIssue<TKey>, Email<TKey>, Feedback<TKey>, IdCard<TKey>, LimitList<TKey>, Log<TKey>, Message<TKey>, Parameter<TKey>, Personal<TKey>, Region<TKey>, SensitiveWord<TKey>, Todo<TKey>, WhiteList<TKey>, Certificate<TKey>, Secret<TKey>, DataSecret<TKey>, Resource<TKey>, ResourceSecret<TKey>, TKey>(options) where TKey : IEquatable<TKey>, IConvertible;

/// <summary>
/// 包含了基础数据对象模型的数据库上下文
/// 此基类上下文因为和身份上下文存在相同两个实体对象模型, 因此不可创建于统一数据库中
/// </summary>
/// <typeparam name="TAttachment"></typeparam>
/// <typeparam name="TDataIssue"></typeparam>
/// <typeparam name="TEmail"></typeparam>
/// <typeparam name="TFeedback"></typeparam>
/// <typeparam name="TIdCard"></typeparam>
/// <typeparam name="TLimitList"></typeparam>
/// <typeparam name="TLog"></typeparam>
/// <typeparam name="TMessage"></typeparam>
/// <typeparam name="TParameter"></typeparam>
/// <typeparam name="TPersonal"></typeparam>
/// <typeparam name="TRegion"></typeparam>
/// <typeparam name="TSensitiveWord"></typeparam>
/// <typeparam name="TTodo"></typeparam>
/// <typeparam name="TWhiteList"></typeparam>
/// <typeparam name="TCertificate"></typeparam>
/// <typeparam name="TSecret"></typeparam>
/// <typeparam name="TDataSecret"></typeparam>
/// <typeparam name="TResource"></typeparam>
/// <typeparam name="TResourceSecret"></typeparam>
/// <typeparam name="TKey"></typeparam>
public class BaseSecurityDbContext<TAttachment, TDataIssue, TEmail, TFeedback, TIdCard, TLimitList, TLog, TMessage, TParameter, TPersonal, TRegion, TSensitiveWord, TTodo, TWhiteList, TCertificate, TSecret, TDataSecret, TResource, TResourceSecret, TKey>(DbContextOptions options) :
    BaseDbContext<TAttachment, TDataIssue, TEmail, TFeedback, TIdCard, TLimitList, TLog, TMessage, TParameter, TPersonal, TRegion, TSensitiveWord, TTodo, TWhiteList, TKey>(options)
    where TAttachment : Attachment<TKey>
    where TDataIssue : DataIssue<TKey>
    where TEmail : Email<TKey>
    where TFeedback : Feedback<TKey>
    where TIdCard : IdCard<TKey>
    where TLimitList : LimitList<TKey>
    where TLog : Log<TKey>
    where TMessage : Message<TKey>
    where TParameter : Parameter<TKey>
    where TPersonal : Personal<TKey>
    where TRegion : Region<TKey>
    where TSensitiveWord : SensitiveWord<TKey>
    where TTodo : Todo<TKey>
    where TWhiteList : WhiteList<TKey>
    where TCertificate : Certificate<TKey>
    where TSecret : Secret<TKey>
    where TDataSecret : DataSecret<TKey>
    where TResource : Resource<TKey>
    where TResourceSecret : ResourceSecret<TKey>
    where TKey : IEquatable<TKey>, IConvertible
{
    #region base entities
    public virtual DbSet<TCertificate> Certificates => Set<TCertificate>();
    public virtual DbSet<TSecret> Secrets => Set<TSecret>();
    public virtual DbSet<TDataSecret> DataSecrets => Set<TDataSecret>();
    public virtual DbSet<TResource> Resources => Set<TResource>();
    public virtual DbSet<TResourceSecret> ResourceSecrets => Set<TResourceSecret>();
    #endregion

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<TCertificate>(b =>
        {
            b.Property(x => x.State).HasDefaultValue(DataState.Available);
            b.Property(x => x.IdentityType).HasDefaultValue(IdentityType.User);
            b.Property(x => x.HashAlgorithm).HasDefaultValue(HashAlgorithm.SHA256);
            b.Property(x => x.EncryptionAlgorithm).HasDefaultValue(SymmetricAlgorithm.AES_256_CBC);
            b.Property(x => x.SignatureAlgorithm).HasDefaultValue(EncryptionAlgorithm.RSA);
        });

        builder.Entity<TSecret>(b =>
        {
            b.Property(x => x.State).HasDefaultValue(DataState.Available);
            b.Property(x => x.IdentityType).HasDefaultValue(IdentityType.User);
            b.Property(x => x.HashAlgorithm).HasDefaultValue(HashAlgorithm.SHA256);
            b.Property(x => x.EncryptionAlgorithm).HasDefaultValue(SymmetricAlgorithm.AES_256_CBC);
            b.Property(x => x.CipherMode).HasDefaultValue(System.Security.Cryptography.CipherMode.CBC);
        });

        builder.Entity<TDataSecret>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TResource>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
        builder.Entity<TResourceSecret>(b => b.Property(x => x.State).HasDefaultValue(DataState.Available));
    }
}